﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace NExtension.Tests
{
    [TestFixture]
    public class EnumeratorTests
    {
        [Test]
        public void TestForEach()
        {
            int count = 0;
            Enumerable.Range(1, 10).ForEach(i => count += i);
            Assert.AreEqual(55, count);
        }

        [Test]
        public void TestForEachWithIndex()
        {
            int counti = 0;
            int countj = 0;
            Enumerable.Range(1, 10).ForEach((i, j) => { counti += i; countj += j; });
            Assert.AreEqual(55, counti);
            Assert.AreEqual(45, countj);
        }

        [Test]
        public void TestAtLeast()
        {
            Assert.IsTrue(Enumerable.Range(1, 10).AtLeast(9), "At least 9 of 10");
            Assert.IsTrue(Enumerable.Range(1, 10).AtLeast(10), "At least 10 of 10");
            Assert.IsFalse(Enumerable.Range(1, 10).AtLeast(11), "At least 11 of 10");
        }

        [Test]
        public void TestAtLeastWithPredicate()
        {
            Assert.IsTrue(Enumerable.Range(1, 10).AtLeast(4, i => i % 2 == 0), "At least 4 even numbers between 1 and 10 (there are 5)");
            Assert.IsTrue(Enumerable.Range(1, 10).AtLeast(5, i => i % 2 == 0), "At least 5 even numbers between 1 and 10 (there are 5)");
            Assert.IsFalse(Enumerable.Range(1, 10).AtLeast(6, i => i % 2 == 0), "At least 6 even numbers between 1 and 10 (there are 5)");
        }

        [Test]
        public void TestAtMost()
        {
            Assert.IsTrue(Enumerable.Range(1, 10).AtMost(11), "At most 11 numbers between 1 and 10");
            Assert.IsTrue(Enumerable.Range(1, 10).AtMost(10), "At most 10 numbers between 1 and 10");
            Assert.IsFalse(Enumerable.Range(1, 10).AtMost(9), "At most 9 numbers between 1 and 10");
        }

        [Test]
        public void TestAtMostWithPredicate()
        {
            Assert.IsTrue(Enumerable.Range(1, 10).AtMost(6, i => i % 2 == 0), "At most 6 even numbers between 1 and 10 (there are 5)");
            Assert.IsTrue(Enumerable.Range(1, 10).AtMost(5, i => i % 2 == 0), "At most 5 even numbers between 1 and 10 (there are 5)");
            Assert.IsFalse(Enumerable.Range(1, 10).AtMost(4, i => i % 2 == 0), "At most 4 even numbers between 1 and 10 (there are 5)");
        }

        [Test]
        public void TestScan()
        {
            int[] result = Enumerable.Range(1, 5).Scan((i, j) => i + j).ToArray();
            Assert.AreEqual(4, result.Length);
            Assert.AreEqual(3, result[0]);
            Assert.AreEqual(5, result[1]);
            Assert.AreEqual(7, result[2]);
            Assert.AreEqual(9, result[3]);
        }

        

        [Test]
        public void TestZip()
        {
            int[] result = Enumerable.Range(1, 3) .Zip(new int[] { 3, 2, 1 }, (i, j) => i + j).ToArray();
            Assert.AreEqual(3, result.Length);
            Assert.AreEqual(4, result[0]);
            Assert.AreEqual(4, result[1]);
            Assert.AreEqual(4, result[2]);

            result = Enumerable.Range(1, 4).Zip(new int[] { 3, 2, 1 }, (i, j) => i + j).ToArray();
            Assert.AreEqual(3, result.Length);
            Assert.AreEqual(4, result[0]);
            Assert.AreEqual(4, result[1]);
            Assert.AreEqual(4, result[2]);

            result = Enumerable.Range(1, 3).Zip(new int[] { 3, 2, 1, 0 }, (i, j) => i + j).ToArray();
            Assert.AreEqual(3, result.Length);
            Assert.AreEqual(4, result[0]);
            Assert.AreEqual(4, result[1]);
            Assert.AreEqual(4, result[2]);
        }

        [Test]
        public void TestCycle()
        {
            int[] result = Enumerable.Range(1, 3).Cycle(10).ToArray();
            Assert.AreEqual(1, result[0]);
            Assert.AreEqual(2, result[1]);
            Assert.AreEqual(3, result[2]);
            Assert.AreEqual(1, result[3]);
            Assert.AreEqual(2, result[4]);
            Assert.AreEqual(3, result[5]);
            Assert.AreEqual(1, result[6]);
            Assert.AreEqual(2, result[7]);
            Assert.AreEqual(3, result[8]);
            Assert.AreEqual(1, result[9]);
        }

        [Test]
        public void TestClump()
        {
            int[][] result = Enumerable.Range(1, 8).Clump(3).Select(i => i.ToArray()).ToArray();
            Assert.AreEqual(3, result.Length);
            Assert.AreEqual(3, result[0].Length);
            Assert.AreEqual(3, result[1].Length);
            Assert.AreEqual(2, result[2].Length);
            Assert.AreEqual(1, result[0][0]);
            Assert.AreEqual(2, result[0][1]);
            Assert.AreEqual(3, result[0][2]);
            Assert.AreEqual(4, result[1][0]);
            Assert.AreEqual(5, result[1][1]);
            Assert.AreEqual(6, result[1][2]);
            Assert.AreEqual(7, result[2][0]);
            Assert.AreEqual(8, result[2][1]);
        }
    }
}
